#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <cstring>
#include "InetAddr.hpp"
#include "ThreadPool.hpp"

#include "LockGuard.hpp"
using namespace std;
using task_t = function<void()>;

class Route
{
private:
public:
    Route()
    {
        pthread_mutex_init(&_mutex, nullptr);
    }

    void CheckOnlineUser(InetAddr &who)
    {
        // 用户表是临界资源，需要加锁
        LockGuard lockguard(&_mutex);
        for (auto &user : _online_user)
        {
            if (user == who)
            {
                LOG(DEBUG, "%s is exists!\n", who.AddrStr().c_str());
                return;
            }
        }

        LOG(DEBUG, "%s is not exists,add it!\n", who.AddrStr().c_str());
        _online_user.push_back(who);
    }
    // 下线
    void Offline(InetAddr &who)
    {
        LockGuard lockguard(&_mutex);
        vector<InetAddr>::iterator st = _online_user.begin();
        while (st != _online_user.end())
        {
            if (*st == who)
            {
                _online_user.erase(st);
                LOG(DEBUG, "%s is offline\n", who.AddrStr().c_str());
                break;
            }
            st++;
        }
    }
    void ForwardHelper(int sockfd, const string &message, InetAddr who)
    {
        LockGuard lockguard(&_mutex);
        string send_message = "[" + who.AddrStr() + "]# " + message;

        // 遍历在线用户表，转发给他们
        for (auto &user : _online_user)
        {
            struct sockaddr_in peer = user.Addr();
            LOG(DEBUG, "Forward message to %s\n", user.AddrStr().c_str());
            sendto(sockfd, send_message.c_str(), send_message.size(), 0, (struct sockaddr *)&peer, sizeof(peer));
        }
    }

    // 转发消息给在线用户表
    void Forward(int sockfd, const string &message, InetAddr &who)
    {
        // 查看该用户是否在线，不在线就添加到在线用户中
        CheckOnlineUser(who);

        // 如果用户退出
        if (message == "QUIT" || message == "quit")
        {
            // 下线
            Offline(who);
            return;
        }

        // 创建单例线程池帮助转发

        task_t t = bind(&Route::ForwardHelper, this, sockfd, message, who);
        ThreadPool<task_t>::GetInstance()->Push(t);
    }
    ~Route()
    {
        pthread_mutex_destroy(&_mutex);
    }

private:
    vector<InetAddr> _online_user; // 在线用户表
    pthread_mutex_t _mutex;
};